<template>
  <a-modal
    :title="title"
    width="720px"
    :visible="visible"
    :confirm-loading="confirmLoading"
    @ok="handleOk"
    @cancel="handleCancel"
  >
    <a-form-model
      ref="ruleForm"
      :model="form"
      :rules="rules"
      :label-col="labelCol"
      :wrapper-col="wrapperCol"
      labelAlign="left"
    >
      <a-tabs v-model="tabsActiveKey">
        <a-tab-pane :key="1">
          <span slot="tab">
            <span v-if="!isEdit">Basic</span>
            <span v-else>详情</span>
          </span>
          <a-form-model-item label="客户端Id" prop="clientId" v-if="!isEdit">
            <a-input v-model="form.clientId" />
          </a-form-model-item>
          <a-form-model-item label="客户端名称" prop="clientName">
            <a-input v-model="form.clientName" />
          </a-form-model-item>
          <a-form-model-item label="描述">
            <a-input v-model="form.description" type="textarea" />
          </a-form-model-item>
          <a-form-model-item label="客户端 Uri">
            <a-input v-model="form.clientUri" />
          </a-form-model-item>
          <a-form-model-item class="mb0" label="Logo Uri">
            <a-input v-model="form.logoUri" />
          </a-form-model-item>
          <a-form-model-item class="mb0">
            <a-checkbox v-model="form.requireConsent">
              需要许可
            </a-checkbox>
          </a-form-model-item>
          <template v-if="isEdit">
            <a-form-model-item class="mb0">
              <a-checkbox v-model="form.requireRequestObject">
                需要请求对象
              </a-checkbox>
            </a-form-model-item>
            <a-form-model-item class="mb0">
              <a-checkbox v-model="form.allowRememberConsent">
                允许记住许可
              </a-checkbox>
            </a-form-model-item>
            <a-form-model-item class="mb0">
              <a-checkbox v-model="form.enabled">
                启用
              </a-checkbox>
            </a-form-model-item>
            <a-form-model-item class="mb0">
              <a-checkbox v-model="form.allowOfflineAccess">
                允许离线访问
              </a-checkbox>
            </a-form-model-item>
            <a-form-model-item class="mb0" label="Front-Channel注销URL">
              <a-input v-model="form.frontChannelLogoutUri" />
            </a-form-model-item>
            <a-form-model-item class="mb0">
              <a-checkbox v-model="form.frontChannelLogoutSessionRequired">
                需要Front-Channel注销会话
              </a-checkbox>
            </a-form-model-item>
            <a-form-model-item class="mb0" label="Back-Channel注销URL">
              <a-input v-model="form.backChannelLogoutUri" />
            </a-form-model-item>
            <a-form-model-item class="mb0">
              <a-checkbox v-model="form.backChannelLogoutSessionRequired">
                需要Back-Channel注销会话
              </a-checkbox>
            </a-form-model-item>
            <a-form-model-item class="mb0" label="允许的身份令牌签名算法">
              <a-input v-model="form.allowedIdentityTokenSigningAlgorithms" />
            </a-form-model-item>
          </template>
        </a-tab-pane>
        <a-tab-pane :key="2">
          <span slot="tab">
            <span v-if="!isEdit">Uris</span>
            <a-dropdown v-else>
              <span class="ant-dropdown-link">
                应用程序Uris<a-icon type="down" />
              </span>
              <a-menu slot="overlay">
                <a-menu-item>
                  <a href="javascript:;" @click="handleUriChange(2, 'Callback')">Callback</a>
                </a-menu-item>
                <a-menu-item>
                  <a href="javascript:;" @click="handleUriChange(2, 'Signout')">Signout</a>
                </a-menu-item>
                <a-menu-item>
                  <a href="javascript:;" @click="handleUriChange(2, 'CORS')">CORS</a>
                </a-menu-item>
              </a-menu>
            </a-dropdown>
          </span>
          <template v-if="!isEdit">
            <a-form-model-item label="回调 Url">
              <a-input v-model="form.callbackUrl" />
            </a-form-model-item>
            <a-form-model-item label="Logout Url">
              <a-input v-model="form.logoutUrl" />
            </a-form-model-item>
          </template>
          <template v-else>
            <div>
              <div class="edit-title">{{uriTitle}}</div>
              <a-form-model-item label="Uri" style="margin-bottom:10px;">
                <a-input v-model="inputUri" />
              </a-form-model-item>
              <div style="text-align:right;margin-bottom:10px;">
                <a-button type="primary" @click="handleAddUri">新增</a-button>
              </div>
            </div>
            <a-table
              :rowKey="(r,i)=>i"
              :columns="uriColumns"
              :data-source="uriMap[currentUri]"
              :pagination="false"
              bordered
            >
              <div slot="action" slot-scope="text,record,index">
                <a-button type="primary" @click="handleDeleteUri(index)">删除</a-button>
              </div>
            </a-table>
          </template>
        </a-tab-pane>
        <a-tab-pane :key="3" tab="Secrets">
          <a-button type="primary" @click="$refs.clinetSecretsEdit.showModal()">新增</a-button>
          <a-table
            :rowKey="(r,i)=>i"
            :columns="secretsColumns"
            :data-source="secretsList"
            :pagination="false"
            style="margin-top:10px;"
            bordered
          >
            <span slot="expiration" slot-scope="text">{{text|moment('YYYY-MM-DD')}}</span>
            <div slot="action" slot-scope="text,record,index">
              <a-button type="primary" @click="handleDeleteSecrets(index)">删除</a-button>
            </div>
          </a-table>
        </a-tab-pane>
        <a-tab-pane :key="4">
          <span slot="tab">
            <a-dropdown>
              <span class="ant-dropdown-link">
                资源<a-icon type="down" />
              </span>
              <a-menu slot="overlay">
                <a-menu-item>
                  <a href="javascript:;" @click="handleSourceChange(4, 'Identity')">Identity资源</a>
                </a-menu-item>
                <a-menu-item>
                  <a href="javascript:;" @click="handleSourceChange(4, 'Api')">Api资源</a>
                </a-menu-item>
              </a-menu>
            </a-dropdown>
          </span>
          <template v-if="currentSource == 'Identity'">
            <div class="item-title">Identity资源</div>
            <a-transfer
              :data-source="identityData"
              :titles="['Available', 'Assigned']"
              :target-keys="identityTargetKeys"
              :selected-keys="identitySelectedKeys"
              :render="item => item.title"
              @change="handleIdentityChange"
              @selectChange="handleIdentitySelectChange"
            />
          </template>
          <template v-if="currentSource == 'Api'">
            <div class="item-title">Api资源</div>
            <a-transfer
              :data-source="apiData"
              :titles="['Available', 'Assigned']"
              :target-keys="apiTargetKeys"
              :selected-keys="apiSelectedKeys"
              :render="item => item.title"
              @change="handleApiChange"
              @selectChange="handleApiSelectChange"
            />
          </template>
        </a-tab-pane>
        <a-tab-pane :key="5" v-if="isEdit">
          <span slot="tab">
            <a-dropdown>
              <span class="ant-dropdown-link">
                Advanced<a-icon type="down" />
              </span>
              <a-menu slot="overlay">
                <a-menu-item>
                  <a href="javascript:;" @click="handleAdvanceChange(5, 'Token')">令牌</a>
                </a-menu-item>
                <a-menu-item>
                  <a href="javascript:;" @click="handleAdvanceChange(5, 'Statement')">声明</a>
                </a-menu-item>
                <a-menu-item>
                  <a href="javascript:;" @click="handleAdvanceChange(5, 'Grant')">授予类型</a>
                </a-menu-item>
                <a-menu-item>
                  <a href="javascript:;" @click="handleAdvanceChange(5, 'Restrictions')">Restrictions</a>
                </a-menu-item>
                <a-menu-item>
                  <a href="javascript:;" @click="handleAdvanceChange(5, 'Props')">属性</a>
                </a-menu-item>
              </a-menu>
            </a-dropdown>
          </span>
          <template v-if="currentAdvance == 'Token'">
            <div class="edit-title">令牌</div>
            <a-form-model-item label="Access Token生命周期">
              <a-input-number :min="0" :precision="0" v-model="form.accessTokenLifetime" style="width:100%;" />
            </a-form-model-item>
            <a-form-model-item label="Access Token类型">
              <a-input-number :min="0" :precision="0" v-model="form.accessTokenType" style="width:100%;" />
            </a-form-model-item>
            <a-form-model-item label="许可生命周期">
              <a-input-number :min="0" :precision="0" v-model="form.absoluteRefreshTokenLifetime" style="width:100%;" />
            </a-form-model-item>
            <a-form-model-item label="成对主题盐" class="mb0">
              <a-input v-model="form.pairWiseSubjectSalt" />
            </a-form-model-item>
            <a-form-model-item class="mb0">
              <a-checkbox v-model="form.includeJwtId">
                需要请求对象
              </a-checkbox>
            </a-form-model-item>
            <a-form-model-item label="User Sso Lifetime">
              <a-input-number :min="0" :precision="0" v-model="form.userSsoLifetime" style="width:100%;" />
            </a-form-model-item>
            <a-form-model-item label="User Code Type">
              <a-input v-model="form.userCodeType" />
            </a-form-model-item>
            <a-form-model-item label="Device Code Type" class="mb0">
              <a-input-number :min="0" :precision="0" v-model="form.deviceCodeLifetime" style="width:100%;" />
            </a-form-model-item>
            <a-form-model-item class="mb0">
              <a-checkbox v-model="form.requirePkce">
                要求pkce
              </a-checkbox>
            </a-form-model-item>
            <a-form-model-item class="mb0">
              <a-checkbox v-model="form.requireClientSecret">
                要求客户机密
              </a-checkbox>
            </a-form-model-item>
          </template>
          <template v-if="currentAdvance == 'Statement'">
            <div class="edit-title">声明</div>
            <a-row :gutter="20">
              <a-col :span="12">
                <a-form-model-item label="类型" style="margin-bottom:10px;">
                  <a-input v-model="statement.type" />
                </a-form-model-item>
              </a-col>
              <a-col :span="12">
                <a-form-model-item label="值" style="margin-bottom:10px;">
                  <a-input v-model="statement.value" />
                </a-form-model-item>
              </a-col>
            </a-row>
            <div style="text-align:right;margin-bottom:10px;">
              <a-button type="primary" @click="handleAddStatement">新增</a-button>
            </div>
            <a-form-model-item class="mb0">
              <a-checkbox v-model="form.alwaysSendClientClaims">
                始终发送客户端声明
              </a-checkbox>
            </a-form-model-item>
            <a-table
              :rowKey="(r,i)=>i"
              :columns="statementColumns"
              :data-source="statementData"
              :pagination="false"
              bordered
            >
              <div slot="action" slot-scope="text,record,index">
                <a-button type="primary" @click="handleDeleteStatement(index)">删除</a-button>
              </div>
            </a-table>
          </template>
          <template v-if="currentAdvance == 'Grant'">
            <div class="edit-title">授予类型</div>
            <a-row :gutter="20">
              <a-col :span="24">
                <a-form-model-item label="Grant Type" style="margin-bottom:10px;">
                  <a-select v-model="grantType">
                    <a-select-option value="implicit">
                      implicit
                    </a-select-option>
                    <a-select-option value="authorization_code">
                      authorization_code
                    </a-select-option>
                    <a-select-option value="hybrid">
                      hybrid
                    </a-select-option>
                    <a-select-option value="client_credentials">
                      client_credentials
                    </a-select-option>
                    <a-select-option value="password">
                      password
                    </a-select-option>
                    <a-select-option value="Custom">
                      Custom
                    </a-select-option>
                  </a-select>
                </a-form-model-item>
              </a-col>
            </a-row>
            <div style="text-align:right;margin-bottom:10px;">
              <a-button type="primary" @click="handleAddGrant">新增</a-button>
            </div>
            <a-table
              :rowKey="(r,i)=>i"
              :columns="grantColumns"
              :data-source="grantData"
              :pagination="false"
              bordered
            >
              <div slot="action" slot-scope="text,record,index">
                <a-button type="primary" @click="handleDeleteGrant(index)">删除</a-button>
              </div>
            </a-table>
          </template>
          <template v-if="currentAdvance == 'Restrictions'">
            <div class="edit-title">Restrictions</div>
            <a-row :gutter="20">
              <a-col :span="24">
                <a-form-model-item label="名称" style="margin-bottom:10px;">
                  <a-input v-model="restrictionsName" />
                </a-form-model-item>
              </a-col>
            </a-row>
            <div style="text-align:right;margin-bottom:10px;">
              <a-button type="primary" @click="handleAddRestrictions">新增</a-button>
            </div>
            <a-form-model-item class="mb0">
              <a-checkbox v-model="form.enableLocalLogin">
                启用本地登录
              </a-checkbox>
            </a-form-model-item>
            <a-table
              :rowKey="(r,i)=>i"
              :columns="restrictionsColumns"
              :data-source="restrictionsData"
              :pagination="false"
              bordered
            >
              <div slot="action" slot-scope="text,record,index">
                <a-button type="primary" @click="handleDeleteRestrictions(index)">删除</a-button>
              </div>
            </a-table>
          </template>
          <template v-if="currentAdvance == 'Props'">
            <div class="edit-title">属性</div>
            <a-row :gutter="20">
              <a-col :span="12">
                <a-form-model-item label="Key" style="margin-bottom:10px;">
                  <a-input v-model="propForm.key" />
                </a-form-model-item>
              </a-col>
              <a-col :span="12">
                <a-form-model-item label="值" style="margin-bottom:10px;">
                  <a-input v-model="propForm.value" />
                </a-form-model-item>
              </a-col>
            </a-row>
            <div style="text-align:right;margin-bottom:10px;">
              <a-button type="primary" @click="handleAddProp">新增</a-button>
            </div>
            <a-table
              :rowKey="(r,i)=>i"
              :columns="propColumns"
              :data-source="propData"
              :pagination="false"
              bordered
            >
              <div slot="action" slot-scope="text,record,index">
                <a-button type="primary" @click="handleDeleteProp(index)">删除</a-button>
              </div>
            </a-table>
          </template>
        </a-tab-pane>
      </a-tabs>
    </a-form-model>
    <ClinetSecretsEdit ref="clinetSecretsEdit" @ok="getSecretsInfo"></ClinetSecretsEdit>
  </a-modal>
</template>

<script>
import { getClientDetail, addClient, updateClient } from "@/services/identityServer/client";
import { getAllApi, getAllIdentity } from "@/services/identityServer/identityServer";
import ClinetSecretsEdit from './ClinetSecretsEdit';
const secretsColumns = [
  {
    title: '类型',
    dataIndex: 'type',
  },
  {
    title: '值',
    dataIndex: 'value',
    width: 130
  },
  {
    title: '描述',
    dataIndex: 'description',
    width: 130
  },
  {
    title: '到期',
    dataIndex: 'expiration',
    scopedSlots: { customRender: 'expiration' },
    width: 130
  },
  {
    title: '操作',
    scopedSlots: { customRender: 'action' },
    width: 140
  }
]
const uriColumns = [
  {
    title: 'Uri',
    dataIndex: 'uri',
  },
  {
    title: '操作',
    scopedSlots: { customRender: 'action' },
    width: 140
  }
]
const statementColumns = [
  {
    title: '类型',
    dataIndex: 'type',
  },
  {
    title: '值',
    dataIndex: 'value',
  },
  {
    title: '操作',
    scopedSlots: { customRender: 'action' },
    width: 140
  }
]
const grantColumns = [
  {
    title: 'Grant Type',
    dataIndex: 'grantType',
  },
  {
    title: '操作',
    scopedSlots: { customRender: 'action' },
    width: 140
  }
]
const restrictionsColumns = [
  {
    title: '名称',
    dataIndex: 'provider',
  },
  {
    title: '操作',
    scopedSlots: { customRender: 'action' },
    width: 140
  }
]
const propColumns = [
  {
    title: 'Key',
    dataIndex: 'key',
  },
  {
    title: '值',
    dataIndex: 'value',
  },
  {
    title: '操作',
    scopedSlots: { customRender: 'action' },
    width: 140
  }
]
export default {
  components: {
    ClinetSecretsEdit
  },
  data() {
    return {
      title: '新增',
      visible: false,
      confirmLoading: false,
      tabsActiveKey: 1,
      labelCol: { span: 24 },
      wrapperCol: { span: 24 },
      form: {},
      rules: {
        clientId: [{ required: true, message: "请输入客户端Id", trigger: "blur" }],
        clientName: [{ required: true, message: "请输入客户端名称", trigger: "blur" }]
      },
      isEdit: false,
      secretsColumns,
      secretsList: [],
      // uri
      currentUri: 'Callback',
      inputUri: '',
      uriTitle: '回调 Url',
      uriColumns,
      uriMap: {
        Callback: [],
        Signout: [],
        CORS: []
      },
      // 资源
      currentSource: 'Identity',
      identityData: [],
      identityTargetKeys: [],
      identitySelectedKeys: [],
      apiData: [],
      apiTargetKeys: [],
      apiSelectedKeys: [],
      // advance
      currentAdvance: 'Token',
      statement: {},
      statementColumns,
      statementData: [],
      grantType: '',
      grantColumns,
      grantData: [],
      restrictionsName: '',
      restrictionsColumns,
      restrictionsData: [],
      propForm: {},
      propColumns,
      propData: []
    };
  },
  methods: {
    showModal(id) {
      this.tabsActiveKey = 1;
      this.getSourceData();
      if (id) {
        this.title = '编辑';
        this.isEdit = true;
        this.getDetail(id);
      } else {
        this.title = '新增';
        this.isEdit = false;
      }
      this.visible = true;
    },
    async getSourceData() {
      await getAllApi()
        .then(res => {
          const arr = []
          res.forEach(item => {
            arr.push({
              key: item.name,
              title: item.displayName,
              description: item.displayName
            })
          })
          this.apiData = arr;
        })
      await getAllIdentity()
        .then(res => {
          const arr = [];
          res.forEach(item => {
            arr.push({
              key: item.name,
              title: item.displayName,
              description: item.displayName
            })
          })
          this.identityData = arr;
        })
    },
    getDetail(id) {
      getClientDetail(id)
        .then(res => {
          this.form = res;
          this.secretsList = res.clientSecrets;
          // uri渲染
          res.redirectUris.forEach(item => {
            this.uriMap.Callback.push({ uri: item.redirectUri });
          });
          res.postLogoutRedirectUris.forEach(item => {
            this.uriMap.Signout.push({ uri: item.postLogoutRedirectUri });
          });
          res.allowedCorsOrigins.forEach(item => {
            this.uriMap.CORS.push({ uri: item.origin });
          });
          // 资源渲染
          let identityDataMap = {};
          let apiDataMap = {};
          this.identityData.forEach(item => {
            identityDataMap[item.key] = item;
          })
          this.apiData.forEach(item => {
            apiDataMap[item.key] = item;
          })
          res.allowedScopes.forEach(item => {
            if (identityDataMap[item.scope]) {
              this.identityTargetKeys.push(item.scope);
            }
            if (apiDataMap[item.scope]) {
              this.apiTargetKeys.push(item.scope);
            }
          })
          // advance
          this.statementData = res.claims;
          this.grantData = res.allowedGrantTypes;
          this.restrictionsData = res.identityProviderRestrictions;
          this.propData = res.properties;
        })
    },
    // #region uri
    handleUriChange(tabsActiveKey, currentUri) {
      this.tabsActiveKey = tabsActiveKey;
      this.currentUri = currentUri;
      switch(currentUri) {
        case 'Callback':
          this.uriTitle = '回调Url';
          break;
        case 'Signout':
          this.uriTitle = 'Signout Url';
          break;
        case 'CORS':
          this.uriTitle = '允许的CORS来源';
          break;
      }
    },
    handleAddUri() {
      if (this.inputUri) {
        this.uriMap[this.currentUri].push({
          uri: this.inputUri
        })
        this.inputUri = '';
      }
    },
    handleDeleteUri(index) {
      this.uriMap[this.currentUri].splice(index, 1);
    },
    // #endregion

    // #region secrets
    getSecretsInfo(v) {
      this.secretsList.push(v)
    },
    handleDeleteSecrets(index) {
      this.secretsList.splice(index, 1)
    },
    // #endregion

    // #region 资源
    handleSourceChange(tabsActiveKey, currentSource) {
      this.tabsActiveKey = tabsActiveKey;
      this.currentSource = currentSource;
    },
    handleIdentityChange(nextTargetKeys, direction, moveKeys) {
      this.identityTargetKeys = nextTargetKeys;
    },
    handleIdentitySelectChange(sourceSelectedKeys, targetSelectedKeys) {
      this.identitySelectedKeys = [...sourceSelectedKeys, ...targetSelectedKeys];
    },
    handleApiChange(nextTargetKeys, direction, moveKeys) {
      this.apiTargetKeys = nextTargetKeys;
    },
    handleApiSelectChange(sourceSelectedKeys, targetSelectedKeys) {
      this.apiSelectedKeys = [...sourceSelectedKeys, ...targetSelectedKeys];
    },
    // #endregion

    // #region Advance
    handleAdvanceChange(tabsActiveKey, currentAdvance) {
      this.tabsActiveKey = tabsActiveKey;
      this.currentAdvance = currentAdvance;
    },
    // 声明
    handleAddStatement() {
      if (this.statement.type && this.statement.value) {
        this.statementData.push(this.statement);
        this.statement = {};
      }
    },
    handleDeleteStatement(index) {
      this.statementData.splice(index, 1);
    },
    // 授予类型
    handleAddGrant() {
      if (this.grantType) {
        const hasArr = this.grantData.filter(item => {
          return item.grantType == this.grantType;
        })
        if (hasArr.length == 0) {
          this.grantData.push({
            grantType: this.grantType
          })
        }
      }
    },
    handleDeleteGrant(index) {
      this.grantData.splice(index, 1);
    },
    // restrictions
    handleAddRestrictions() {
      if (this.restrictionsName) {
        this.restrictionsData.push({
          provider: this.restrictionsName
        })
        this.restrictionsName = '';
      }
    },
    handleDeleteRestrictions(index) {
      this.restrictionsData.splice(index, 1);
    },
    // prop
    handleAddProp() {
      if (this.propForm.key && this.propForm.value) {
        this.propData.push(this.propForm);
        this.propForm = {};
      }
    },
    handleDeleteProp(index) {
      this.propData.splice(index, i);
    },
    // #endregion
    handleOk() {
      this.$refs.ruleForm.validate((valid) => {
        if (valid) {
          this.confirmLoading = true;
          const params = {
            ...this.form,
            secrets: this.secretsList,
            scopes: [
              ...this.identityTargetKeys,
              ...this.apiTargetKeys
            ],
            claims: this.statementData,//声明
            allowedGrantTypes: this.grantData.map(item=>item.grantType),//授予类型
            identityProviderRestrictions: this.restrictionsData.map(item=>item.provider),//restrictions
            properties: this.propData,//prop
          }
          if (this.form.id) {
            params.redirectUris = this.uriMap.Callback.map(item => item.uri);
            params.postLogoutRedirectUris = this.uriMap.Signout.map(item => item.uri);
            params.allowedCorsOrigins = this.uriMap.CORS.map(item => item.uri);
            updateClient(this.form.id, params)
              .then((res) => {
                this.$message.success("操作成功");
                this.$emit("ok");
                this.handleCancel();
              })
              .finally(() => {
                this.confirmLoading = false;
              });
          } else {
            addClient(params)
              .then((res) => {
                this.$message.success("操作成功");
                this.$emit("ok");
                this.handleCancel();
              })
              .finally(() => {
                this.confirmLoading = false;
              });
          }
        } else {
          return false;
        }
      });
    },
    handleCancel() {
      this.form = {};

      this.secretsList = [];

      this.uriMap = {
        Callback: [],
        Signout: [],
        CORS: []
      }
      this.identityTargetKeys = [];
      this.identitySelectedKeys = [];
      this.apiTargetKeys = [];
      this.apiSelectedKeys = [];
      
      this.statementData = [];
      this.grantType = '';
      this.grantData = [];
      this.restrictionsData = [];
      this.propData = [];

      this.$refs.ruleForm.clearValidate();
      this.confirmLoading = false;
      this.visible = false;
    },
  },
};
</script>

<style scoped>
.item-title {
  font-size: 24px;
  line-height: 1.5;
  font-weight: 600;
  color: #333;
  margin-bottom: 10px;
}
.edit-title {
  font-size: 18px;
  line-height: 1.5;
  font-weight: 600;
  color: #333;
  margin-bottom: 10px;
}
.mb0 {
  margin-bottom: 0;
}
</style>